#ifndef _TEST_BACKTRACKING_H_
#define _TEST_BACKTRACKING_H_
#include <cppunit/extensions/HelperMacros.h>

class Test_backtracking: public CppUnit::TestFixture
{
	CPPUNIT_TEST_SUITE( Test_backtracking);
	CPPUNIT_TEST (test_LU_Solver_01);
	CPPUNIT_TEST (test_LU_Solver_02);
	CPPUNIT_TEST (test_Heun_01);
	CPPUNIT_TEST (test_Heun_02);
	CPPUNIT_TEST (test_cross_product);

	CPPUNIT_TEST (test_is_in_face_01);
	CPPUNIT_TEST (test_is_in_face_02);

	CPPUNIT_TEST (test_map_sixpoint_to_plane_01);
	CPPUNIT_TEST (test_map_sixpoint_to_plane_02);
	CPPUNIT_TEST (test_map_threepoint_to_plane_01);
	CPPUNIT_TEST (test_map_threepoint_to_plane_02);

	CPPUNIT_TEST (test_convert_coordinate_01);
	CPPUNIT_TEST (test_convert_coordinate_02);
	CPPUNIT_TEST (test_convert_coordinate_03);
	CPPUNIT_TEST (test_convert_coordinate_04);

	CPPUNIT_TEST (test_intersection_01);
	CPPUNIT_TEST (test_intersection_02);
	CPPUNIT_TEST (test_intersection_03);
	CPPUNIT_TEST (test_intersection_04);

	CPPUNIT_TEST (test_six_points_interpolation_01);
	CPPUNIT_TEST (test_six_points_interpolation_02);
	CPPUNIT_TEST (test_six_points_interpolation_03);
	CPPUNIT_TEST (test_six_points_interpolation_04);

	CPPUNIT_TEST (test_vertex_point_next_face_01);
	CPPUNIT_TEST (test_vertex_point_next_face_02);

//	CPPUNIT_TEST (test_draw_geodesics_01);
//	CPPUNIT_TEST (test_draw_geodesics_01_2);
//	CPPUNIT_TEST (test_draw_geodesics_02);
//	CPPUNIT_TEST (test_draw_geodesics_03);
//	CPPUNIT_TEST (test_draw_geodesics_04);

	


	//CPPUNIT_TEST (test_draw_geodesics_01);
	CPPUNIT_TEST_SUITE_END();
public:
	void setUp();
	void tearDown();
	void test_LU_Solver_01();
	void test_LU_Solver_02();
	void test_cross_product();
	void test_Heun_01();
	void test_Heun_02();
	
	void test_is_in_face_01();
	void test_is_in_face_02();

	void test_map_sixpoint_to_plane_01();
	void test_map_sixpoint_to_plane_02();
	void test_map_threepoint_to_plane_01();
	void test_map_threepoint_to_plane_02();
	void test_convert_coordinate_01();
	void test_convert_coordinate_02();
	void test_convert_coordinate_03();
	void test_convert_coordinate_04();

	void test_intersection_01();
	void test_intersection_02();
	void test_intersection_03();
	void test_intersection_04();

	void test_six_points_interpolation_01();
	void test_six_points_interpolation_02();
	void test_six_points_interpolation_03();
	void test_six_points_interpolation_04();

	void test_vertex_point_next_face_01();
	void test_vertex_point_next_face_02();

	void test_draw_geodesics_01();
	void test_draw_geodesics_01_2();
	void test_draw_geodesics_02();
	void test_draw_geodesics_03();
	void test_draw_geodesics_04();

	//void test_draw_geodesics_01();
public:
	/*
	static CppUnit::Test * suite()
	{
		CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite("Test_geodesics" );
	suiteOfTests->addTest( new CppUnit::TestCaller<Test_geodesics>( 
                                   "test_LU_solver", 
                                   &Test_geodesics::test_LU_solver ) );
	return suiteOfTests;	

	}
	*/
private:
	typedef Backtracking <double>::MATRIX		MATRIX;
	typedef Backtracking <double>::SCALAR		SCALAR;
	typedef Backtracking <double>::VECTOR		VECTOR;
	typedef Backtracking <double>::POINT		POINT; 
	typedef Backtracking <double>::ARRAY		ARRAY;
	typedef Backtracking <double>::SEGMENT		SEGMENT; 
	//void test_draw_geodesics_generic(const char * argv, int start_vertex_index, unsigned center_face_idx);

	//there are some functions which help to check the errors of models
private:
	bool read_check_manifold_model(Mesh & mesh, std::string filename)
	{
		OpenMesh::IO::Options ropt, wopt;

		if (! OpenMesh::IO::read_mesh(mesh, filename.c_str(), ropt))
		{
			std::cerr<<"Error loading mesh from file "<<filename.c_str()<<std::endl;
			return false;
		}
		//cout<<mesh.n_vertices()<<endl;
		//unsigned n_vertices = mesh.n_vertices();
		//Mesh::VertexIter v_it, v_end (mesh.vertices_end());
	
		//Mesh::VertexHandle v_handle = mesh.vertex_handle(0);
		//cout<<mesh.point (v_handle)<<endl;

		Mesh::VertexIter v_it, v_end (mesh.vertices_end());
		for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
		{
			if (! mesh.is_manifold(v_it) )
			{
				std::cerr<<"Not manifold"<<std::endl;
				return false;
			}
		}
		return true;
	}

	void vertex_point_fmm (Mesh & mesh, int vertex_idx)
	{
		std::vector<Mesh::VertexHandle> boundary;
		boundary.push_back(mesh.vertex_handle(vertex_idx));
		mesh.data(mesh.vertex_handle(vertex_idx)).set_distance(0);
		fast_marching (mesh, boundary);
	}
	void vertex_point_set_fmm (Mesh& mesh, std::vector<int> point_idx_set)
	{
		std::vector<Mesh::VertexHandle> boundary;
		for (unsigned i = 0;i < point_idx_set.size(); ++i)
		{
			boundary.push_back(mesh.vertex_handle(point_idx_set[i]));
			mesh.data(mesh.vertex_handle(point_idx_set[i])).set_distance(0);
			mesh.data(mesh.vertex_handle(point_idx_set[i])).set_state(ALIVE);
		}
		fast_marching (mesh, boundary);
	}
	void face_centroid_fmm (Mesh & mesh, int face_idx)
	{
		POINT centroid (0,0,0); 
		Mesh::FaceHandle start_face = mesh.face_handle(face_idx);
		for (Mesh::FaceVertexIter fv_it  = mesh.fv_iter(start_face); fv_it; ++fv_it)
		{
		
			centroid [0] +=mesh.point(fv_it)[0];
			centroid [1] +=mesh.point(fv_it)[1];
			centroid [2] +=mesh.point(fv_it)[2];
		}
		centroid [0] /= 3.0f;
		centroid [1] /= 3.0f;
		centroid [2] /= 3.0f;

		face_point_fmm (mesh, face_idx, centroid);
	}

};


#endif
